<!DOCTYPE html>
<html lang="zh_cn">
<head>
          <title>来玩魔王的咚</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <meta charset="utf-8" />
        <!-- twitter card metadata -->
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="/images/mowang.png">
<meta name="twitter:site" content="">
<meta name="twitter:title" content="排序（sort包）">
<meta name="twitter:description" content="<p>使用sort.Interface来排序：接口实现，字符串排序，反转Reverse；复杂类型的排序：对结构体排序，使用表格输出结构体（text/tabwriter包），优化及多字段排序，检查是否有序；稳定的排序方法</p>">
        <!-- OG Tags -->
<meta property="og:url" content="/gopl-pkg-sort.html"/>
<meta property="og:title" content="来玩魔王的咚 | 排序（sort包）" />
<meta property="og:description" content="<p>使用sort.Interface来排序：接口实现，字符串排序，反转Reverse；复杂类型的排序：对结构体排序，使用表格输出结构体（text/tabwriter包），优化及多字段排序，检查是否有序；稳定的排序方法</p>" />
        <!-- favicon -->
        <link rel="icon" type="image/png" href="/images/mowang.png">
        <!-- moment.js for date formatting -->
        <script src="/theme/js/moment.js"></script>
        <!-- css -->
        <link rel="stylesheet" type="text/css" href="/theme/css/main.css" />
        <!-- 左边的menu，如果页面高度不够，就跟着滚动，否则文章分类显示不全 -->
        <link rel="stylesheet" type="text/css" href="/theme/css/mycss/menu.css" />
		<script>
			
                /*! grunt-grunticon Stylesheet Loader - v2.1.2 | https://github.com/filamentgroup/grunticon | (c) 2015 Scott Jehl, Filament Group, Inc. | MIT license. */
    
    (function(e){function t(t,n,r,o){"use strict";function a(){for(var e,n=0;u.length>n;n++)u[n].href&&u[n].href.indexOf(t)>-1&&(e=!0);e?i.media=r||"all":setTimeout(a)}var i=e.document.createElement("link"),l=n||e.document.getElementsByTagName("script")[0],u=e.document.styleSheets;return i.rel="stylesheet",i.href=t,i.media="only x",i.onload=o||null,l.parentNode.insertBefore(i,l),a(),i}var n=function(r,o){"use strict";if(r&&3===r.length){var a=e.navigator,i=e.Image,l=!(!document.createElementNS||!document.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect||!document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image","1.1")||e.opera&&-1===a.userAgent.indexOf("Chrome")||-1!==a.userAgent.indexOf("Series40")),u=new i;u.onerror=function(){n.method="png",n.href=r[2],t(r[2])},u.onload=function(){var e=1===u.width&&1===u.height,a=r[e&&l?0:e?1:2];n.method=e&&l?"svg":e?"datapng":"png",n.href=a,t(a,null,null,o)},u.src="",document.documentElement.className+=" grunticon"}};n.loadCSS=t,e.grunticon=n})(this);(function(e,t){"use strict";var n=t.document,r="grunticon:",o=function(e){if(n.attachEvent?"complete"===n.readyState:"loading"!==n.readyState)e();else{var t=!1;n.addEventListener("readystatechange",function(){t||(t=!0,e())},!1)}},a=function(e){return t.document.querySelector('link[href$="'+e+'"]')},c=function(e){var t,n,o,a,c,i,u={};if(t=e.sheet,!t)return u;n=t.cssRules?t.cssRules:t.rules;for(var l=0;n.length>l;l++)o=n[l].cssText,a=r+n[l].selectorText,c=o.split(");")[0].match(/US\-ASCII\,([^"']+)/),c&&c[1]&&(i=decodeURIComponent(c[1]),u[a]=i);return u},i=function(e){var t,o,a;o="data-grunticon-embed";for(var c in e)if(a=c.slice(r.length),t=n.querySelectorAll(a+"["+o+"]"),t.length)for(var i=0;t.length>i;i++)t[i].innerHTML=e[c],t[i].style.backgroundImage="none",t[i].removeAttribute(o);return t},u=function(t){"svg"===e.method&&o(function(){i(c(a(e.href))),"function"==typeof t&&t()})};e.embedIcons=i,e.getCSS=a,e.getIcons=c,e.ready=o,e.svgLoadedCallback=u,e.embedSVG=u})(grunticon,this);
                
                grunticon(["/theme/css/icons.data.svg.css", "/theme/css/icons.data.png.css", "/theme/css/icons.fallback.css"]);
            </script>
        <noscript><link href="/theme/css/icons.fallback.css" rel="stylesheet"></noscript>
        <!-- menu toggle javascript -->
        <script type="text/javascript">
            document.addEventListener("DOMContentLoaded", initMenu);
            
            function initMenu(){
                var menu = document.getElementById("menu");
                var menulink = document.getElementById("menu-link");
                menulink.addEventListener("click", function toggleMenu(){
                        window.event.preventDefault();
                        menulink.classList.toggle('active');
                        menu.classList.toggle('active');              
                    });
            };
        </script>
        <!-- 不蒜子 -->
        <script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

    <meta name="description" content="<p>使用sort.Interface来排序：接口实现，字符串排序，反转Reverse；复杂类型的排序：对结构体排序，使用表格输出结构体（text/tabwriter包），优化及多字段排序，检查是否有序；稳定的排序方法</p>" />

    <meta name="tags" content="gopl" />
    <meta name="tags" content="sort" />
  <!-- 替换部分base的样式，看文章时，要再宽一点，右边有很多空间可以撑开 -->
  <link rel="stylesheet" type="text/css" href="/theme/css/mycss/article.css" />

</head>
<body>
    <div role="banner" id="masthead">
        <header>
            <a href="/"><img src="/images/mowang.png" alt="McManus Logo"></a>
                <h1>来玩魔王的咚@骑士救兵</h1>
            <a href="#menu" id="menu-link">more stuff</a>
            <nav id="menu">
                <ul>
                        <li><a href="/tags">tags</a></li>
                            <li><a href="/category/cloud.html">Cloud</a></li>
                            <li><a href="/category/docker.html">Docker</a></li>
                            <li class="active"><a href="/category/go.html">Go</a></li>
                            <li><a href="/category/linux.html">Linux</a></li>
                            <li><a href="/category/python.html">Python</a></li>
                            <li><a href="/category/xue-xi-bi-ji.html">学习笔记</a></li>
                            <li><a href="/category/yun-wei-zi-dong-hua.html">运维自动化</a></li>
                </ul>
            </nav>
        </header>
    </div>
        <div class="page" role="main">
  <div class="article" role="article">
    <article>
        <footer>
            <a name="top"></a>
            <p>
              <time datetime=" 2020-07-23 14:10:00+08:00">
                <script>document.write(moment('2020-07-23 14:10:00+08:00').format('LL'));</script>
              </time>
              ~
              <time datetime=" 2020-07-23 14:10:00+08:00">
                <script>document.write(moment('2020-07-23 14:10:00+08:00').format('LL'));</script>
              </time>
            </p>
        </footer>
        <header>
          <h2>
            排序（sort包）
          </h2>
        </header>
      <div class="content">
         <div class="toc">
<ul>
<li><a href="#shi-yong-sortinterface-lai-pai-xu">使用 sort.Interface 来排序</a><ul>
<li><a href="#jie-kou-shi-xian">接口实现</a></li>
<li><a href="#zi-fu-chuan-pai-xu">字符串排序</a></li>
<li><a href="#fan-zhuan-reverse">反转 Reverse</a></li>
</ul>
</li>
<li><a href="#fu-za-lei-xing-de-pai-xu">复杂类型的排序</a><ul>
<li><a href="#shu-ju-he-jie-gou">数据和结构</a></li>
<li><a href="#yong-biao-ge-shu-chu-jie-gou-ti">用表格输出结构体</a></li>
<li><a href="#pai-xu">排序</a></li>
<li><a href="#you-hua">优化</a></li>
<li><a href="#jian-cha-shi-fou-you-xu">检查是否有序</a></li>
<li><a href="#wan-zheng-shi-li-dai-ma">完整示例代码</a></li>
</ul>
</li>
<li><a href="#wen-ding-de-pai-xu">稳定的排序</a><ul>
<li><a href="#zhun-bei-shu-ju">准备数据</a></li>
<li><a href="#jie-kou-shi-xian_1">接口实现</a></li>
<li><a href="#bu-wen-ding-de-pai-xu">不稳定的排序</a></li>
<li><a href="#wen-ding-de-pai-xu_1">稳定的排序</a></li>
<li><a href="#xiao-jie">小结</a></li>
</ul>
</li>
</ul>
</div>
<h3 id="shi-yong-sortinterface-lai-pai-xu"><a class="toclink" href="#shi-yong-sortinterface-lai-pai-xu">使用 sort.Interface 来排序</a></h3>
<p>排序是一个在很多程序中广泛使用的操作。sort 包提供了针对任意序列根据任意排序函数原地排序的功能。<br>
这样的设计号称并不常见。在很多语言中，排序算法跟序列数据类型绑定，排序函数跟序列元素类型绑定。但 Go 语言的 sort.Sort 函数对序列和其中元素的布局无任何要求，它使用 sort.Interface 接口来实现。  </p>
<h4 id="jie-kou-shi-xian"><a class="toclink" href="#jie-kou-shi-xian">接口实现</a></h4>
<p>一个原地排序算法需要知道三个信息：</p>
<ol>
<li>序列长度</li>
<li>比较两个元素的含义</li>
<li>如何交换两个元素</li>
</ol>
<p>所以 sort.Interface 接口就有三个方法：</p>
<div class="highlight"><pre><span></span><code><span class="kn">package</span><span class="w"> </span><span class="nx">sort</span><span class="w"></span>

<span class="kd">type</span><span class="w"> </span><span class="nx">Interface</span><span class="w"> </span><span class="kd">interface</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">Len</span><span class="p">()</span><span class="w"> </span><span class="kt">int</span><span class="w"></span>
<span class="w">    </span><span class="nx">Less</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"></span>
<span class="w">    </span><span class="nx">Swap</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<h4 id="zi-fu-chuan-pai-xu"><a class="toclink" href="#zi-fu-chuan-pai-xu">字符串排序</a></h4>
<p>要对序列排序，需要先确定一个实现了上面三个方法的类型，接着把 sort.Sort 函数应用到上面这类方法的示例上。<br>
以字符串切片 []string 为例，定义一个新的类型 StringSlice 以及它的三个方法如下：</p>
<div class="highlight"><pre><span></span><code><span class="kd">type</span><span class="w"> </span><span class="nx">StringSlice</span><span class="w"> </span><span class="p">[]</span><span class="kt">string</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">p</span><span class="w"> </span><span class="nx">StringSlice</span><span class="p">)</span><span class="w"> </span><span class="nx">Len</span><span class="p">()</span><span class="w"> </span><span class="kt">int</span><span class="w">           </span><span class="p">{</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">len</span><span class="p">(</span><span class="nx">p</span><span class="p">)</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">p</span><span class="w"> </span><span class="nx">StringSlice</span><span class="p">)</span><span class="w"> </span><span class="nx">Less</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">p</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">p</span><span class="p">[</span><span class="nx">j</span><span class="p">]</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">p</span><span class="w"> </span><span class="nx">StringSlice</span><span class="p">)</span><span class="w"> </span><span class="nx">Swap</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w">      </span><span class="p">{</span><span class="w"> </span><span class="nx">p</span><span class="p">[</span><span class="nx">i</span><span class="p">],</span><span class="w"> </span><span class="nx">p</span><span class="p">[</span><span class="nx">j</span><span class="p">]</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">p</span><span class="p">[</span><span class="nx">j</span><span class="p">],</span><span class="w"> </span><span class="nx">p</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>现在要对一个字符串切片进行排序，先把类型转换为 StringSlice 类型，然后调用 sort.Sort 函数即可：</p>
<div class="highlight"><pre><span></span><code><span class="nx">sort</span><span class="p">.</span><span class="nx">Sort</span><span class="p">(</span><span class="nx">StringSlice</span><span class="p">(</span><span class="nx">names</span><span class="p">))</span><span class="w"></span>
</code></pre></div>

<p>字符串切片的排序太常见了，所以 sort 包提供了 StringSLice 类型，以及一个直接排序的 Strings 函数。上面对 StringSlice 类型及其方法的定义就是源码里实现的代码。  </p>
<p>所以要对字符串切片进行排序，直接调用 srot.Strings 函数即可：</p>
<div class="highlight"><pre><span></span><code><span class="nx">sort</span><span class="p">.</span><span class="nx">Strings</span><span class="p">(</span><span class="nx">names</span><span class="p">)</span><span class="w"></span>
</code></pre></div>

<p>为了简便，sort 包专门对 []int、[]string、[]float64 这三个类型提供了排序的函数和相关类型。对于其他类型，就需要自己写了，不过写起来也不复杂。  </p>
<h4 id="fan-zhuan-reverse"><a class="toclink" href="#fan-zhuan-reverse">反转 Reverse</a></h4>
<p>sort.Reverse 函数值得仔细看一下，它使用了一个重要的概念<strong>组合</strong>。sort 包定义了一个 reverse 类型，这个类型是一个嵌入了 sort.Interface 的结构。reverse 的 Less 方法，直接调用内嵌的 sort.Interface 值的 Less 方法，但是调换了下标。<br>
这样就实现了颠倒排序的结果了：</p>
<div class="highlight"><pre><span></span><code><span class="kn">package</span><span class="w"> </span><span class="nx">sort</span><span class="w"></span>

<span class="kd">type</span><span class="w"> </span><span class="nx">reverse</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">Interface</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="c1">// 这个是在sort包里的，所以就是 sort.Interface</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">r</span><span class="w"> </span><span class="nx">reverse</span><span class="p">)</span><span class="w"> </span><span class="nx">Less</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">r</span><span class="p">.</span><span class="nx">Interface</span><span class="p">.</span><span class="nx">Less</span><span class="p">(</span><span class="nx">j</span><span class="p">,</span><span class="w"> </span><span class="nx">i</span><span class="p">)</span><span class="w"> </span><span class="p">}</span><span class="w">  </span><span class="c1">// 这里调换了函数体中 i 和 j 的位置</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="nx">Reverse</span><span class="p">(</span><span class="nx">data</span><span class="w"> </span><span class="nx">Interface</span><span class="p">)</span><span class="w"> </span><span class="nx">Interface</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="o">&amp;</span><span class="nx">reverse</span><span class="p">{</span><span class="nx">data</span><span class="p">}</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>reverse 的另外两个方法 Len 和 Swap，没有定义，就会由内嵌的 sort.Interface 隐式提供。导出函数 Reverse 则返回一个包含原始的 sort.Interface 值的 reverse 实例。<br>
最终反转排序的调用如下，先做类型转换，然后加一步通过 Reverse 函数生成 reverse 实例，最后就是调用 sort.Sort 函数完成排序：</p>
<div class="highlight"><pre><span></span><code><span class="nx">sort</span><span class="p">.</span><span class="nx">Sort</span><span class="p">(</span><span class="nx">sort</span><span class="p">.</span><span class="nx">Reverse</span><span class="p">(</span><span class="nx">StringSlice</span><span class="p">(</span><span class="nx">names</span><span class="p">)))</span><span class="w"></span>
</code></pre></div>

<h3 id="fu-za-lei-xing-de-pai-xu"><a class="toclink" href="#fu-za-lei-xing-de-pai-xu">复杂类型的排序</a></h3>
<p>对于一个复杂的类型，比如结构体，它会有多个字段，也就是可能需要对多个维度进行排序。  </p>
<h4 id="shu-ju-he-jie-gou"><a class="toclink" href="#shu-ju-he-jie-gou">数据和结构</a></h4>
<p>下面是一个复杂的结构体类型，并且数据也已经准备好了：</p>
<div class="highlight"><pre><span></span><code><span class="kd">type</span><span class="w"> </span><span class="nx">Track</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">Title</span><span class="w">  </span><span class="kt">string</span><span class="w"></span>
<span class="w">    </span><span class="nx">Artist</span><span class="w"> </span><span class="kt">string</span><span class="w"></span>
<span class="w">    </span><span class="nx">Album</span><span class="w">  </span><span class="kt">string</span><span class="w"></span>
<span class="w">    </span><span class="nx">Year</span><span class="w">   </span><span class="kt">int</span><span class="w"></span>
<span class="w">    </span><span class="nx">Length</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Duration</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">var</span><span class="w"> </span><span class="nx">tracks</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="p">[]</span><span class="o">*</span><span class="nx">Track</span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="p">{</span><span class="s">&quot;Go&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Delilah&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;From the Roots Up&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">2012</span><span class="p">,</span><span class="w"> </span><span class="nx">length</span><span class="p">(</span><span class="s">&quot;3m38s&quot;</span><span class="p">)},</span><span class="w"></span>
<span class="w">    </span><span class="p">{</span><span class="s">&quot;Go&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Moby&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Moby&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">1992</span><span class="p">,</span><span class="w"> </span><span class="nx">length</span><span class="p">(</span><span class="s">&quot;3m37s&quot;</span><span class="p">)},</span><span class="w"></span>
<span class="w">    </span><span class="p">{</span><span class="s">&quot;Go Ahead&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Alicia Keys&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;As I Am&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">2007</span><span class="p">,</span><span class="w"> </span><span class="nx">length</span><span class="p">(</span><span class="s">&quot;4m36s&quot;</span><span class="p">)},</span><span class="w"></span>
<span class="w">    </span><span class="p">{</span><span class="s">&quot;Ready 2 Go&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Martin Solveig&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Smash&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">2011</span><span class="p">,</span><span class="w"> </span><span class="nx">length</span><span class="p">(</span><span class="s">&quot;4m24s&quot;</span><span class="p">)},</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">length</span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Duration</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">d</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">ParseDuration</span><span class="p">(</span><span class="nx">s</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nb">panic</span><span class="p">(</span><span class="nx">s</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="nx">d</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<h4 id="yong-biao-ge-shu-chu-jie-gou-ti"><a class="toclink" href="#yong-biao-ge-shu-chu-jie-gou-ti">用表格输出结构体</a></h4>
<p>这里使用 text/tabwriter 包可以生成一个干净整洁的表格。这里注意，*tabwriter.Writer 满足 io.Writer 接口，先用它收集所有写入的数据，在 Flush 方法调用时才会格式化整个表格并且输出：</p>
<div class="highlight"><pre><span></span><code><span class="kd">func</span><span class="w"> </span><span class="nx">printTracks</span><span class="p">(</span><span class="nx">tracks</span><span class="w"> </span><span class="p">[]</span><span class="o">*</span><span class="nx">Track</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">const</span><span class="w"> </span><span class="nx">format</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">&quot;%v\t%v\t%v\t%v\t%v\t\n&quot;</span><span class="w"></span>
<span class="w">    </span><span class="nx">tw</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">new</span><span class="p">(</span><span class="nx">tabwriter</span><span class="p">.</span><span class="nx">Writer</span><span class="p">).</span><span class="nx">Init</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Stdout</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">8</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="sc">&#39; &#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Fprintf</span><span class="p">(</span><span class="nx">tw</span><span class="p">,</span><span class="w"> </span><span class="nx">format</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Title&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Artist&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Album&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Year&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Length&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Fprintf</span><span class="p">(</span><span class="nx">tw</span><span class="p">,</span><span class="w"> </span><span class="nx">format</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;-----&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;------&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;-----&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;----&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;------&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="nx">_</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">tracks</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Fprintf</span><span class="p">(</span><span class="nx">tw</span><span class="p">,</span><span class="w"> </span><span class="nx">format</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">.</span><span class="nx">Title</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">.</span><span class="nx">Artist</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">.</span><span class="nx">Album</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">.</span><span class="nx">Year</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">.</span><span class="nx">Length</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">tw</span><span class="p">.</span><span class="nx">Flush</span><span class="p">()</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<h4 id="pai-xu"><a class="toclink" href="#pai-xu">排序</a></h4>
<p>按照 Artist 字段进行排序：</p>
<div class="highlight"><pre><span></span><code><span class="kd">type</span><span class="w"> </span><span class="nx">byArtist</span><span class="w"> </span><span class="p">[]</span><span class="o">*</span><span class="nx">Track</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">x</span><span class="w"> </span><span class="nx">byArtist</span><span class="p">)</span><span class="w"> </span><span class="nx">Len</span><span class="p">()</span><span class="w"> </span><span class="kt">int</span><span class="w">           </span><span class="p">{</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">len</span><span class="p">(</span><span class="nx">x</span><span class="p">)</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">x</span><span class="w"> </span><span class="nx">byArtist</span><span class="p">)</span><span class="w"> </span><span class="nx">Less</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">x</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">Artist</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">x</span><span class="p">[</span><span class="nx">j</span><span class="p">].</span><span class="nx">Artist</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">x</span><span class="w"> </span><span class="nx">byArtist</span><span class="p">)</span><span class="w"> </span><span class="nx">Swap</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w">      </span><span class="p">{</span><span class="w"> </span><span class="nx">x</span><span class="p">[</span><span class="nx">i</span><span class="p">],</span><span class="w"> </span><span class="nx">x</span><span class="p">[</span><span class="nx">j</span><span class="p">]</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">x</span><span class="p">[</span><span class="nx">j</span><span class="p">],</span><span class="w"> </span><span class="nx">x</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>按照 Year 字段进行排序：</p>
<div class="highlight"><pre><span></span><code><span class="kd">type</span><span class="w"> </span><span class="nx">byYear</span><span class="w"> </span><span class="p">[]</span><span class="o">*</span><span class="nx">Track</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">x</span><span class="w"> </span><span class="nx">byYear</span><span class="p">)</span><span class="w"> </span><span class="nx">Len</span><span class="p">()</span><span class="w"> </span><span class="kt">int</span><span class="w">           </span><span class="p">{</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">len</span><span class="p">(</span><span class="nx">x</span><span class="p">)</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">x</span><span class="w"> </span><span class="nx">byYear</span><span class="p">)</span><span class="w"> </span><span class="nx">Less</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">x</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">Year</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">x</span><span class="p">[</span><span class="nx">j</span><span class="p">].</span><span class="nx">Year</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">x</span><span class="w"> </span><span class="nx">byYear</span><span class="p">)</span><span class="w"> </span><span class="nx">Swap</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w">      </span><span class="p">{</span><span class="w"> </span><span class="nx">x</span><span class="p">[</span><span class="nx">i</span><span class="p">],</span><span class="w"> </span><span class="nx">x</span><span class="p">[</span><span class="nx">j</span><span class="p">]</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">x</span><span class="p">[</span><span class="nx">j</span><span class="p">],</span><span class="w"> </span><span class="nx">x</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
</code></pre></div>

<h4 id="you-hua"><a class="toclink" href="#you-hua">优化</a></h4>
<p>上面分别对2个字段定义了排序。像这样，对于每一个排序都需要实现一个新的 sort.Interface。但是其实只有 Less 方法不同，而 Len 和 Swap 方法都是一样的。<br>
在下面的例子中，具体类型 customSort 组合了一个要排序的切片类型和一个函数，这样每次只要写一个比较函数就可以定义一个新的排序。<br>
从这个例子也可以看到，实现 sort.Interface 的具体类型并不一定都是切片，比如这里的 customSort 就是一个结构体：</p>
<div class="highlight"><pre><span></span><code><span class="kd">type</span><span class="w"> </span><span class="nx">customSort</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">t</span><span class="w">    </span><span class="p">[]</span><span class="o">*</span><span class="nx">Track</span><span class="w"></span>
<span class="w">    </span><span class="nx">less</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span><span class="w"> </span><span class="nx">y</span><span class="w"> </span><span class="o">*</span><span class="nx">Track</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">x</span><span class="w"> </span><span class="nx">customSort</span><span class="p">)</span><span class="w"> </span><span class="nx">Len</span><span class="p">()</span><span class="w"> </span><span class="kt">int</span><span class="w">           </span><span class="p">{</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">len</span><span class="p">(</span><span class="nx">x</span><span class="p">.</span><span class="nx">t</span><span class="p">)</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">x</span><span class="w"> </span><span class="nx">customSort</span><span class="p">)</span><span class="w"> </span><span class="nx">Less</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">less</span><span class="p">(</span><span class="nx">x</span><span class="p">.</span><span class="nx">t</span><span class="p">[</span><span class="nx">i</span><span class="p">],</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">t</span><span class="p">[</span><span class="nx">j</span><span class="p">])</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">x</span><span class="w"> </span><span class="nx">customSort</span><span class="p">)</span><span class="w"> </span><span class="nx">Swap</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w">      </span><span class="p">{</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">t</span><span class="p">[</span><span class="nx">i</span><span class="p">],</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">t</span><span class="p">[</span><span class="nx">j</span><span class="p">]</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">t</span><span class="p">[</span><span class="nx">j</span><span class="p">],</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">t</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>接下来就定义一个多层的比较函数，先对 Title 排序，然后对 Year，最后是时长：</p>
<div class="highlight"><pre><span></span><code><span class="nx">sort</span><span class="p">.</span><span class="nx">Sort</span><span class="p">(</span><span class="nx">customSort</span><span class="p">{</span><span class="nx">tracks</span><span class="p">,</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span><span class="w"> </span><span class="nx">y</span><span class="w"> </span><span class="o">*</span><span class="nx">Track</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">Title</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="nx">y</span><span class="p">.</span><span class="nx">Title</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">Title</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">y</span><span class="p">.</span><span class="nx">Title</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">Year</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="nx">y</span><span class="p">.</span><span class="nx">Year</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">Year</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">y</span><span class="p">.</span><span class="nx">Year</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">Length</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="nx">y</span><span class="p">.</span><span class="nx">Length</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">Length</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">y</span><span class="p">.</span><span class="nx">Length</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="kc">false</span><span class="w"></span>
<span class="p">}})</span><span class="w"></span>
</code></pre></div>

<h4 id="jian-cha-shi-fou-you-xu"><a class="toclink" href="#jian-cha-shi-fou-you-xu">检查是否有序</a></h4>
<p>一个长度为 n 的序列进行排序需要 O(n logn) 次比较操作，而判断一个序列是否已经排好序值需要最多 (n-1) 次比较。<br>
sort 包提供的 IsSorted 函数可以判断序列是否是排好序的:</p>
<div class="highlight"><pre><span></span><code><span class="nx">values</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="p">[]</span><span class="kt">int</span><span class="p">{</span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">4</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">}</span><span class="w"></span>
<span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">sort</span><span class="p">.</span><span class="nx">IntsAreSorted</span><span class="p">(</span><span class="nx">values</span><span class="p">))</span><span class="w">                         </span><span class="c1">// &quot;false&quot;</span><span class="w"></span>
<span class="nx">sort</span><span class="p">.</span><span class="nx">Ints</span><span class="p">(</span><span class="nx">values</span><span class="p">)</span><span class="w">                                               </span><span class="c1">// 排序</span><span class="w"></span>
<span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">values</span><span class="p">)</span><span class="w">                                             </span><span class="c1">// &quot;[1 1 3 4]&quot;</span><span class="w"></span>
<span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">sort</span><span class="p">.</span><span class="nx">IntsAreSorted</span><span class="p">(</span><span class="nx">values</span><span class="p">))</span><span class="w">                         </span><span class="c1">// &quot;true&quot;</span><span class="w"></span>
<span class="nx">sort</span><span class="p">.</span><span class="nx">Sort</span><span class="p">(</span><span class="nx">sort</span><span class="p">.</span><span class="nx">Reverse</span><span class="p">(</span><span class="nx">sort</span><span class="p">.</span><span class="nx">IntSlice</span><span class="p">(</span><span class="nx">values</span><span class="p">)))</span><span class="w">                  </span><span class="c1">// 反转</span><span class="w"></span>
<span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">values</span><span class="p">)</span><span class="w">                                             </span><span class="c1">// &quot;[4 3 1 1]&quot;</span><span class="w"></span>
<span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">sort</span><span class="p">.</span><span class="nx">IntsAreSorted</span><span class="p">(</span><span class="nx">values</span><span class="p">))</span><span class="w">                         </span><span class="c1">// &quot;false&quot;</span><span class="w"></span>
<span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">sort</span><span class="p">.</span><span class="nx">IsSorted</span><span class="p">(</span><span class="nx">sort</span><span class="p">.</span><span class="nx">Reverse</span><span class="p">(</span><span class="nx">sort</span><span class="p">.</span><span class="nx">IntSlice</span><span class="p">(</span><span class="nx">values</span><span class="p">))))</span><span class="w"> </span><span class="c1">// &quot;true&quot;</span><span class="w"></span>
</code></pre></div>

<h4 id="wan-zheng-shi-li-dai-ma"><a class="toclink" href="#wan-zheng-shi-li-dai-ma">完整示例代码</a></h4>
<p>上面的代码的源码文件，可以运行：</p>
<div class="highlight"><pre><span></span><code><span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w"></span>

<span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;fmt&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;os&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;sort&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;text/tabwriter&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;time&quot;</span><span class="w"></span>
<span class="p">)</span><span class="w"></span>

<span class="kd">type</span><span class="w"> </span><span class="nx">Track</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">Title</span><span class="w">  </span><span class="kt">string</span><span class="w"></span>
<span class="w">    </span><span class="nx">Artist</span><span class="w"> </span><span class="kt">string</span><span class="w"></span>
<span class="w">    </span><span class="nx">Album</span><span class="w">  </span><span class="kt">string</span><span class="w"></span>
<span class="w">    </span><span class="nx">Year</span><span class="w">   </span><span class="kt">int</span><span class="w"></span>
<span class="w">    </span><span class="nx">Length</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Duration</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">var</span><span class="w"> </span><span class="nx">tracks</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="p">[]</span><span class="o">*</span><span class="nx">Track</span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="p">{</span><span class="s">&quot;Go&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Delilah&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;From the Roots Up&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">2012</span><span class="p">,</span><span class="w"> </span><span class="nx">length</span><span class="p">(</span><span class="s">&quot;3m38s&quot;</span><span class="p">)},</span><span class="w"></span>
<span class="w">    </span><span class="p">{</span><span class="s">&quot;Go&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Moby&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Moby&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">1992</span><span class="p">,</span><span class="w"> </span><span class="nx">length</span><span class="p">(</span><span class="s">&quot;3m37s&quot;</span><span class="p">)},</span><span class="w"></span>
<span class="w">    </span><span class="p">{</span><span class="s">&quot;Go Ahead&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Alicia Keys&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;As I Am&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">2007</span><span class="p">,</span><span class="w"> </span><span class="nx">length</span><span class="p">(</span><span class="s">&quot;4m36s&quot;</span><span class="p">)},</span><span class="w"></span>
<span class="w">    </span><span class="p">{</span><span class="s">&quot;Ready 2 Go&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Martin Solveig&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Smash&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">2011</span><span class="p">,</span><span class="w"> </span><span class="nx">length</span><span class="p">(</span><span class="s">&quot;4m24s&quot;</span><span class="p">)},</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">length</span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Duration</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">d</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">ParseDuration</span><span class="p">(</span><span class="nx">s</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nb">panic</span><span class="p">(</span><span class="nx">s</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="nx">d</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">printTracks</span><span class="p">(</span><span class="nx">tracks</span><span class="w"> </span><span class="p">[]</span><span class="o">*</span><span class="nx">Track</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">const</span><span class="w"> </span><span class="nx">format</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">&quot;%v\t%v\t%v\t%v\t%v\t\n&quot;</span><span class="w"></span>
<span class="w">    </span><span class="nx">tw</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">new</span><span class="p">(</span><span class="nx">tabwriter</span><span class="p">.</span><span class="nx">Writer</span><span class="p">).</span><span class="nx">Init</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Stdout</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">8</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="sc">&#39; &#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Fprintf</span><span class="p">(</span><span class="nx">tw</span><span class="p">,</span><span class="w"> </span><span class="nx">format</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Title&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Artist&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Album&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Year&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Length&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Fprintf</span><span class="p">(</span><span class="nx">tw</span><span class="p">,</span><span class="w"> </span><span class="nx">format</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;-----&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;------&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;-----&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;----&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;------&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="nx">_</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">tracks</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Fprintf</span><span class="p">(</span><span class="nx">tw</span><span class="p">,</span><span class="w"> </span><span class="nx">format</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">.</span><span class="nx">Title</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">.</span><span class="nx">Artist</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">.</span><span class="nx">Album</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">.</span><span class="nx">Year</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">.</span><span class="nx">Length</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">tw</span><span class="p">.</span><span class="nx">Flush</span><span class="p">()</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">type</span><span class="w"> </span><span class="nx">byArtist</span><span class="w"> </span><span class="p">[]</span><span class="o">*</span><span class="nx">Track</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">x</span><span class="w"> </span><span class="nx">byArtist</span><span class="p">)</span><span class="w"> </span><span class="nx">Len</span><span class="p">()</span><span class="w"> </span><span class="kt">int</span><span class="w">           </span><span class="p">{</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">len</span><span class="p">(</span><span class="nx">x</span><span class="p">)</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">x</span><span class="w"> </span><span class="nx">byArtist</span><span class="p">)</span><span class="w"> </span><span class="nx">Less</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">x</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">Artist</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">x</span><span class="p">[</span><span class="nx">j</span><span class="p">].</span><span class="nx">Artist</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">x</span><span class="w"> </span><span class="nx">byArtist</span><span class="p">)</span><span class="w"> </span><span class="nx">Swap</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w">      </span><span class="p">{</span><span class="w"> </span><span class="nx">x</span><span class="p">[</span><span class="nx">i</span><span class="p">],</span><span class="w"> </span><span class="nx">x</span><span class="p">[</span><span class="nx">j</span><span class="p">]</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">x</span><span class="p">[</span><span class="nx">j</span><span class="p">],</span><span class="w"> </span><span class="nx">x</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span><span class="w"> </span><span class="p">}</span><span class="w"></span>

<span class="kd">type</span><span class="w"> </span><span class="nx">byYear</span><span class="w"> </span><span class="p">[]</span><span class="o">*</span><span class="nx">Track</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">x</span><span class="w"> </span><span class="nx">byYear</span><span class="p">)</span><span class="w"> </span><span class="nx">Len</span><span class="p">()</span><span class="w"> </span><span class="kt">int</span><span class="w">           </span><span class="p">{</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">len</span><span class="p">(</span><span class="nx">x</span><span class="p">)</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">x</span><span class="w"> </span><span class="nx">byYear</span><span class="p">)</span><span class="w"> </span><span class="nx">Less</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">x</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">Year</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">x</span><span class="p">[</span><span class="nx">j</span><span class="p">].</span><span class="nx">Year</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">x</span><span class="w"> </span><span class="nx">byYear</span><span class="p">)</span><span class="w"> </span><span class="nx">Swap</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w">      </span><span class="p">{</span><span class="w"> </span><span class="nx">x</span><span class="p">[</span><span class="nx">i</span><span class="p">],</span><span class="w"> </span><span class="nx">x</span><span class="p">[</span><span class="nx">j</span><span class="p">]</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">x</span><span class="p">[</span><span class="nx">j</span><span class="p">],</span><span class="w"> </span><span class="nx">x</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span><span class="w"> </span><span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;byArtist:&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">sort</span><span class="p">.</span><span class="nx">Sort</span><span class="p">(</span><span class="nx">byArtist</span><span class="p">(</span><span class="nx">tracks</span><span class="p">))</span><span class="w"></span>
<span class="w">    </span><span class="nx">printTracks</span><span class="p">(</span><span class="nx">tracks</span><span class="p">)</span><span class="w"></span>

<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;\nReverse(byArtist):&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">sort</span><span class="p">.</span><span class="nx">Sort</span><span class="p">(</span><span class="nx">sort</span><span class="p">.</span><span class="nx">Reverse</span><span class="p">(</span><span class="nx">byArtist</span><span class="p">(</span><span class="nx">tracks</span><span class="p">)))</span><span class="w"></span>
<span class="w">    </span><span class="nx">printTracks</span><span class="p">(</span><span class="nx">tracks</span><span class="p">)</span><span class="w"></span>

<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;\nbyYear:&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">sort</span><span class="p">.</span><span class="nx">Sort</span><span class="p">(</span><span class="nx">byYear</span><span class="p">(</span><span class="nx">tracks</span><span class="p">))</span><span class="w"></span>
<span class="w">    </span><span class="nx">printTracks</span><span class="p">(</span><span class="nx">tracks</span><span class="p">)</span><span class="w"></span>

<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;\nCustom:&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">sort</span><span class="p">.</span><span class="nx">Sort</span><span class="p">(</span><span class="nx">customSort</span><span class="p">{</span><span class="nx">tracks</span><span class="p">,</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span><span class="w"> </span><span class="nx">y</span><span class="w"> </span><span class="o">*</span><span class="nx">Track</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">Title</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="nx">y</span><span class="p">.</span><span class="nx">Title</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">Title</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">y</span><span class="p">.</span><span class="nx">Title</span><span class="w"></span>
<span class="w">        </span><span class="p">}</span><span class="w"></span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">Year</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="nx">y</span><span class="p">.</span><span class="nx">Year</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">Year</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">y</span><span class="p">.</span><span class="nx">Year</span><span class="w"></span>
<span class="w">        </span><span class="p">}</span><span class="w"></span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">Length</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="nx">y</span><span class="p">.</span><span class="nx">Length</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">Length</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">y</span><span class="p">.</span><span class="nx">Length</span><span class="w"></span>
<span class="w">        </span><span class="p">}</span><span class="w"></span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="kc">false</span><span class="w"></span>
<span class="w">    </span><span class="p">}})</span><span class="w"></span>
<span class="w">    </span><span class="nx">printTracks</span><span class="p">(</span><span class="nx">tracks</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">type</span><span class="w"> </span><span class="nx">customSort</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">t</span><span class="w">    </span><span class="p">[]</span><span class="o">*</span><span class="nx">Track</span><span class="w"></span>
<span class="w">    </span><span class="nx">less</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span><span class="w"> </span><span class="nx">y</span><span class="w"> </span><span class="o">*</span><span class="nx">Track</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">x</span><span class="w"> </span><span class="nx">customSort</span><span class="p">)</span><span class="w"> </span><span class="nx">Len</span><span class="p">()</span><span class="w"> </span><span class="kt">int</span><span class="w">           </span><span class="p">{</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">len</span><span class="p">(</span><span class="nx">x</span><span class="p">.</span><span class="nx">t</span><span class="p">)</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">x</span><span class="w"> </span><span class="nx">customSort</span><span class="p">)</span><span class="w"> </span><span class="nx">Less</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">less</span><span class="p">(</span><span class="nx">x</span><span class="p">.</span><span class="nx">t</span><span class="p">[</span><span class="nx">i</span><span class="p">],</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">t</span><span class="p">[</span><span class="nx">j</span><span class="p">])</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">x</span><span class="w"> </span><span class="nx">customSort</span><span class="p">)</span><span class="w"> </span><span class="nx">Swap</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w">      </span><span class="p">{</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">t</span><span class="p">[</span><span class="nx">i</span><span class="p">],</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">t</span><span class="p">[</span><span class="nx">j</span><span class="p">]</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">t</span><span class="p">[</span><span class="nx">j</span><span class="p">],</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">t</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span><span class="w"> </span><span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">init</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">values</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="p">[]</span><span class="kt">int</span><span class="p">{</span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">4</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">sort</span><span class="p">.</span><span class="nx">IntsAreSorted</span><span class="p">(</span><span class="nx">values</span><span class="p">))</span><span class="w">                         </span><span class="c1">// &quot;false&quot;</span><span class="w"></span>
<span class="w">    </span><span class="nx">sort</span><span class="p">.</span><span class="nx">Ints</span><span class="p">(</span><span class="nx">values</span><span class="p">)</span><span class="w">                                               </span><span class="c1">// 排序</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">values</span><span class="p">)</span><span class="w">                                             </span><span class="c1">// &quot;[1 1 3 4]&quot;</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">sort</span><span class="p">.</span><span class="nx">IntsAreSorted</span><span class="p">(</span><span class="nx">values</span><span class="p">))</span><span class="w">                         </span><span class="c1">// &quot;true&quot;</span><span class="w"></span>
<span class="w">    </span><span class="nx">sort</span><span class="p">.</span><span class="nx">Sort</span><span class="p">(</span><span class="nx">sort</span><span class="p">.</span><span class="nx">Reverse</span><span class="p">(</span><span class="nx">sort</span><span class="p">.</span><span class="nx">IntSlice</span><span class="p">(</span><span class="nx">values</span><span class="p">)))</span><span class="w">                  </span><span class="c1">// 反转</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">values</span><span class="p">)</span><span class="w">                                             </span><span class="c1">// &quot;[4 3 1 1]&quot;</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">sort</span><span class="p">.</span><span class="nx">IntsAreSorted</span><span class="p">(</span><span class="nx">values</span><span class="p">))</span><span class="w">                         </span><span class="c1">// &quot;false&quot;</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">sort</span><span class="p">.</span><span class="nx">IsSorted</span><span class="p">(</span><span class="nx">sort</span><span class="p">.</span><span class="nx">Reverse</span><span class="p">(</span><span class="nx">sort</span><span class="p">.</span><span class="nx">IntSlice</span><span class="p">(</span><span class="nx">values</span><span class="p">))))</span><span class="w"> </span><span class="c1">// &quot;true&quot;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<h3 id="wen-ding-de-pai-xu"><a class="toclink" href="#wen-ding-de-pai-xu">稳定的排序</a></h3>
<p>sort.Sort 是不稳定的排序。在“优化”章节里的例子，先对Title进行比较，然后是Year，再是Length，实现了多个字段的排序。在第一关键字相等的情况下，再通过第二关键字进行比较。整个过程只进行了一次序列的交换，这样看不出问题。<br>
如果对多个关键字进行排序，但是不是像上面这样通过一次比较交换完成，而是先对一个关键字进行排序，得到一个已经有序的序列。然后再在这个序列的基础上，再进行一次对另一个关键字的排序，稳定的排序和不稳定的排序的结果就会有差别。比如排序第一关键字是年龄，第二关键字是姓名。那么先做一个姓名的排序（稳定不稳定无所谓），然后再在原来的基础上做一次年龄的排序（必须稳定），才能得到正确的结果。下面通过具体事例来说明，稳定排序和不稳定排序的差别。  </p>
<h4 id="zhun-bei-shu-ju"><a class="toclink" href="#zhun-bei-shu-ju">准备数据</a></h4>
<p>数据结构、打印的函数、具体数据如下代码实现：</p>
<div class="highlight"><pre><span></span><code><span class="kd">type</span><span class="w"> </span><span class="nx">Student</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">name</span><span class="w"> </span><span class="kt">string</span><span class="w"></span>
<span class="w">    </span><span class="nx">age</span><span class="w">  </span><span class="kt">int</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">var</span><span class="w"> </span><span class="nx">students</span><span class="w"> </span><span class="p">[]</span><span class="o">*</span><span class="nx">Student</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">printStudents</span><span class="p">(</span><span class="nx">students</span><span class="w"> </span><span class="p">[]</span><span class="o">*</span><span class="nx">Student</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">const</span><span class="w"> </span><span class="nx">format</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">&quot;%v\t%v\t\n&quot;</span><span class="w"></span>
<span class="w">    </span><span class="nx">tw</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">new</span><span class="p">(</span><span class="nx">tabwriter</span><span class="p">.</span><span class="nx">Writer</span><span class="p">).</span><span class="nx">Init</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Stdout</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">8</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="sc">&#39; &#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Fprintf</span><span class="p">(</span><span class="nx">tw</span><span class="p">,</span><span class="w"> </span><span class="nx">format</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;name&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;age&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Fprintf</span><span class="p">(</span><span class="nx">tw</span><span class="p">,</span><span class="w"> </span><span class="nx">format</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;----&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;---&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="nx">_</span><span class="p">,</span><span class="w"> </span><span class="nx">s</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">students</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Fprintf</span><span class="p">(</span><span class="nx">tw</span><span class="p">,</span><span class="w"> </span><span class="nx">format</span><span class="p">,</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">name</span><span class="p">,</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">age</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">tw</span><span class="p">.</span><span class="nx">Flush</span><span class="p">()</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">init</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">students</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="p">[]</span><span class="o">*</span><span class="nx">Student</span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="o">&amp;</span><span class="nx">Student</span><span class="p">{</span><span class="s">&quot;Adam&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">20</span><span class="p">},</span><span class="w"></span>
<span class="w">        </span><span class="o">&amp;</span><span class="nx">Student</span><span class="p">{</span><span class="s">&quot;Bob&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">18</span><span class="p">},</span><span class="w"></span>
<span class="w">        </span><span class="o">&amp;</span><span class="nx">Student</span><span class="p">{</span><span class="s">&quot;Clark&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">19</span><span class="p">},</span><span class="w"></span>
<span class="w">        </span><span class="o">&amp;</span><span class="nx">Student</span><span class="p">{</span><span class="s">&quot;Daisy&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">18</span><span class="p">},</span><span class="w"></span>
<span class="w">        </span><span class="o">&amp;</span><span class="nx">Student</span><span class="p">{</span><span class="s">&quot;Eva&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">20</span><span class="p">},</span><span class="w"></span>
<span class="w">        </span><span class="o">&amp;</span><span class="nx">Student</span><span class="p">{</span><span class="s">&quot;Frank&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">20</span><span class="p">},</span><span class="w"></span>
<span class="w">        </span><span class="o">&amp;</span><span class="nx">Student</span><span class="p">{</span><span class="s">&quot;Gideon&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">19</span><span class="p">},</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<h4 id="jie-kou-shi-xian_1"><a class="toclink" href="#jie-kou-shi-xian_1">接口实现</a></h4>
<p>这里使用通用的 less 方法：</p>
<div class="highlight"><pre><span></span><code><span class="kd">type</span><span class="w"> </span><span class="nx">studentSort</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">s</span><span class="w">    </span><span class="p">[]</span><span class="o">*</span><span class="nx">Student</span><span class="w"></span>
<span class="w">    </span><span class="nx">less</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span><span class="w"> </span><span class="nx">y</span><span class="w"> </span><span class="o">*</span><span class="nx">Student</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">x</span><span class="w"> </span><span class="nx">studentSort</span><span class="p">)</span><span class="w"> </span><span class="nx">Len</span><span class="p">()</span><span class="w"> </span><span class="kt">int</span><span class="w">           </span><span class="p">{</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">len</span><span class="p">(</span><span class="nx">x</span><span class="p">.</span><span class="nx">s</span><span class="p">)</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">x</span><span class="w"> </span><span class="nx">studentSort</span><span class="p">)</span><span class="w"> </span><span class="nx">Less</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">less</span><span class="p">(</span><span class="nx">x</span><span class="p">.</span><span class="nx">s</span><span class="p">[</span><span class="nx">i</span><span class="p">],</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">s</span><span class="p">[</span><span class="nx">j</span><span class="p">])</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">x</span><span class="w"> </span><span class="nx">studentSort</span><span class="p">)</span><span class="w"> </span><span class="nx">Swap</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w">      </span><span class="p">{</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">s</span><span class="p">[</span><span class="nx">i</span><span class="p">],</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">s</span><span class="p">[</span><span class="nx">j</span><span class="p">]</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">s</span><span class="p">[</span><span class="nx">j</span><span class="p">],</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">s</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
</code></pre></div>

<h4 id="bu-wen-ding-de-pai-xu"><a class="toclink" href="#bu-wen-ding-de-pai-xu">不稳定的排序</a></h4>
<p>先对 name 进行排序，然后再原来序列的基础上对 age 进行排序：</p>
<div class="highlight"><pre><span></span><code><span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">sort</span><span class="p">.</span><span class="nx">Sort</span><span class="p">(</span><span class="nx">studentSort</span><span class="p">{</span><span class="nx">students</span><span class="p">,</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span><span class="w"> </span><span class="nx">y</span><span class="w"> </span><span class="o">*</span><span class="nx">Student</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">name</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="nx">y</span><span class="p">.</span><span class="nx">name</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">name</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">y</span><span class="p">.</span><span class="nx">name</span><span class="w"></span>
<span class="w">        </span><span class="p">}</span><span class="w"></span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="kc">false</span><span class="w"></span>
<span class="w">    </span><span class="p">}})</span><span class="w"></span>

<span class="w">    </span><span class="nx">sort</span><span class="p">.</span><span class="nx">Sort</span><span class="p">(</span><span class="nx">studentSort</span><span class="p">{</span><span class="nx">students</span><span class="p">,</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span><span class="w"> </span><span class="nx">y</span><span class="w"> </span><span class="o">*</span><span class="nx">Student</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">age</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="nx">y</span><span class="p">.</span><span class="nx">age</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">age</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">y</span><span class="p">.</span><span class="nx">age</span><span class="w"></span>
<span class="w">        </span><span class="p">}</span><span class="w"></span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="kc">false</span><span class="w"></span>
<span class="w">    </span><span class="p">}})</span><span class="w"></span>
<span class="w">    </span><span class="nx">printStudents</span><span class="p">(</span><span class="nx">students</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>最后打印的结果是这样的：</p>
<div class="highlight"><pre><span></span><code>PS H:\Go\src\gopl\output\sort\stable&gt; go run main.go
name    age
----    ---
Bob     18
Daisy   18
Gideon  19
Clark   19
Eva     20
Frank   20
Adam    20
PS H:\Go\src\gopl\output\sort\stable&gt;
</code></pre></div>

<p>在这个结果里年龄相同的数据，并没有按字母顺序排序，虽然之前已经按字母顺序进行了排序，不过在第二次排序的时候，会把之前的顺序打乱，这就是不稳定的排序。  </p>
<h4 id="wen-ding-de-pai-xu_1"><a class="toclink" href="#wen-ding-de-pai-xu_1">稳定的排序</a></h4>
<p>这里来看看稳定的排序。这里只要把 sort.Sort 函数替换成 sort.Stable 即可：</p>
<div class="highlight"><pre><span></span><code><span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">sort</span><span class="p">.</span><span class="nx">Sort</span><span class="p">(</span><span class="nx">studentSort</span><span class="p">{</span><span class="nx">students</span><span class="p">,</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span><span class="w"> </span><span class="nx">y</span><span class="w"> </span><span class="o">*</span><span class="nx">Student</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">name</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="nx">y</span><span class="p">.</span><span class="nx">name</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">name</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">y</span><span class="p">.</span><span class="nx">name</span><span class="w"></span>
<span class="w">        </span><span class="p">}</span><span class="w"></span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="kc">false</span><span class="w"></span>
<span class="w">    </span><span class="p">}})</span><span class="w"></span>

<span class="w">    </span><span class="nx">sort</span><span class="p">.</span><span class="nx">Stable</span><span class="p">(</span><span class="nx">studentSort</span><span class="p">{</span><span class="nx">students</span><span class="p">,</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span><span class="w"> </span><span class="nx">y</span><span class="w"> </span><span class="o">*</span><span class="nx">Student</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">age</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="nx">y</span><span class="p">.</span><span class="nx">age</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">age</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">y</span><span class="p">.</span><span class="nx">age</span><span class="w"></span>
<span class="w">        </span><span class="p">}</span><span class="w"></span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="kc">false</span><span class="w"></span>
<span class="w">    </span><span class="p">}})</span><span class="w"></span>
<span class="w">    </span><span class="nx">printStudents</span><span class="p">(</span><span class="nx">students</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>这里只替换了第二次排序的函数。第一次排序的时候假设序列本来就是乱的，所以这里并没有需要稳定的必要。<br>
这次再来看下结果：</p>
<div class="highlight"><pre><span></span><code>PS H:\Go\src\gopl\output\sort\stable&gt; go run main.go
name    age
----    ---
Bob     18
Daisy   18
Clark   19
Gideon  19
Adam    20
Eva     20
Frank   20
PS H:\Go\src\gopl\output\sort\stable&gt;
</code></pre></div>

<p>这次的结果是期望的样子了，按年龄排序，如果年龄相同，再按字母顺序排序。  </p>
<h4 id="xiao-jie"><a class="toclink" href="#xiao-jie">小结</a></h4>
<p>sort.Stable 虽然能保证排序的稳定性，但是牺牲了效率。如果需要保证序列的稳定性，那么就要用 sort.Stable 函数来代替 sort.Sort。<br>
但是如果仅仅只是要对多个字段进行排序，也可以直接在比较的时候就完成全部字段的比较，仅做一次序列的调换（就是排序）。就向上面“优化”章节里的 customSort 实现的那样。<br>
下面是这里例子里的实现：</p>
<div class="highlight"><pre><span></span><code><span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">sort</span><span class="p">.</span><span class="nx">Sort</span><span class="p">(</span><span class="nx">studentSort</span><span class="p">{</span><span class="nx">students</span><span class="p">,</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span><span class="w"> </span><span class="nx">y</span><span class="w"> </span><span class="o">*</span><span class="nx">Student</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">age</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="nx">y</span><span class="p">.</span><span class="nx">age</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">age</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">y</span><span class="p">.</span><span class="nx">age</span><span class="w"></span>
<span class="w">        </span><span class="p">}</span><span class="w"></span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">name</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="nx">y</span><span class="p">.</span><span class="nx">name</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">x</span><span class="p">.</span><span class="nx">name</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">y</span><span class="p">.</span><span class="nx">name</span><span class="w"></span>
<span class="w">        </span><span class="p">}</span><span class="w"></span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="kc">false</span><span class="w"></span>
<span class="w">    </span><span class="p">}})</span><span class="w"></span>
<span class="w">    </span><span class="nx">printStudents</span><span class="p">(</span><span class="nx">students</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
      </div>
      <div class="back-to-top">
        <a href="/">HOME</a>
        <a href="#top">TOP</a>
      </div>
    </article>
  </div>
<!-- end article -->
<!-- 页面往下滚动一段之后才会显示TOC -->
<script>
  window.onscroll = function() {
    var tocbox = document.getElementsByClassName('toc')[0];
    var osTop = document.documentElement.scrollTop || document.body.scrollTop;
    var osWidth = document.documentElement.scrollWidth || document.body.scrollWidth;
    // console.log(osTop)
    if (osTop>300 && osWidth>865) {
      tocbox.style.display = "block"
    }
    if (osTop<300 || osWidth<865) {
      tocbox.style.display = "none"
    }
  }
</script>
                <footer>
                    <div class="icons">
                    </div>
                    <span id="busuanzi_container_page_pv" style="padding: 10px">本文阅读量<span id="busuanzi_value_page_pv"></span>次</span>
                    <span id="busuanzi_container_site_pv" style="padding: 10px">本站总访问量<span id="busuanzi_value_site_pv"></span>次</span>
                    <span id="busuanzi_container_site_uv" style="padding: 10px">本站总访客数<span id="busuanzi_value_site_uv"></span>人</span>
                    <p>© <script>document.write(moment().format('YYYY'));</script> 749B</p>
                </footer>
        </div>
</body>
</html>